/*
 * 文件名： WechatSdkPayManager.java
 * 
 * 工程名称: bis-manager
 *
 * Gopay
 *
 * 创建日期： 2016年8月5日
 *
 * Copyright(C) 2016, by www.gopay.com.cn Inc.All rights reserved.
 *
 * 原始作者: 宣广海
 *
 */
package com.gopay.bis.manager.bank.scan;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.gopay.bis.dao.bankorder.BankCustAppInfoDAO;
import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.dao.bankorder.BankOrderDAO;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BankOrder;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.CustAppInfo;
import com.gopay.common.domain.bank.ScanPayBaseMessage;
import com.gopay.common.domain.bank.wechat.sdk.req.SdkOrderQueryReqMsg;
import com.gopay.common.domain.bank.wechat.sdk.req.SdkPayReqMsg;
import com.gopay.common.domain.bank.wechat.sdk.req.SdkRefundQueryReqMsg;
import com.gopay.common.domain.bank.wechat.sdk.req.SdkRefundReqMsg;
import com.gopay.common.exception.GopayException;
import com.gopay.remote.bank.businesses.ScanPayService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;

/**
 * 微信Sdk业务报文拼装处理
 *
 * @author 宣广海
 *
 * @version
 *
 * @since 2016年8月5日
 */
@Service("wechatSdkPayManager")
public class WechatSdkPayManager {

	/**
	 * 注入对象
	 */
	@Resource(name = "wechatSdkPayServiceClient")
	private ScanPayService wechatSdkPayServiceClient;

	@Resource(name = "wechatSdkPayConfig")
	private Map<String, String> wechatSdkPayConfig;

	@Resource(name = "bankOrderDAO")
	private BankOrderDAO bankOrderDAO;

	@Resource(name = "bankCustAppInfoDAO")
	private BankCustAppInfoDAO bankCustAppInfoDAO;

	/**
	 * 定义日志对象
	 */
	private static Logger logger = LoggerFactory.getLogger(WechatSdkPayManager.class);
	public Object verify(BaseMessage baseMsg) throws GopayException {
		boolean falg = false;
		BankLogUtils.printWeChatManagerVerifySendLog(baseMsg);
		/**
		 * 根据订单号获取APPid,根据APPID获取商户号及商户KEY
		 */
		buildMchInfo(baseMsg);

		falg = (boolean) wechatSdkPayServiceClient.verify(baseMsg);
		BankLogUtils.printWeChatManagerVerifyReturnLog(baseMsg, falg);
		return falg;
	}

	public Object payment(BaseMessage baseMsg) throws GopayException {
		ScanPayBaseMessage scanPayMsg = (ScanPayBaseMessage) baseMsg;
		
		/**
		 * 根据订单号获取APPid,根据APPID获取商户号及商户KEY
		 */
		buildPaymentMchInfo(baseMsg);
		SdkPayReqMsg payMsg = new SdkPayReqMsg();
		baseMsg.setBankOrderId(modifyOrderId(baseMsg.getOrderId(),baseMsg.getBankIntrChann().value));
		try {
			BeanUtils.copyProperties(baseMsg, payMsg);
			payMsg.setService(wechatSdkPayConfig.get("WECHATSDK.PAY.SEVICE"));
			payMsg.setVersion(wechatSdkPayConfig.get("WECHATSDK.PAY.VERSION"));
			payMsg.setCharset(wechatSdkPayConfig.get("WECHATSDK.PAY.CHARSET"));
			payMsg.setSign_type(wechatSdkPayConfig.get("WECHATSDK.PAY.SIGN.TYPE"));
			/**
			 * 商户号
			 */
			payMsg.setMch_id(baseMsg.getMerID());
			/**
			 * 商户号密钥
			 */
			payMsg.setMchKey(baseMsg.getMchKey());
			// payMsg.setBankOrderId(modifyOrderId(payMsg.getOrderId()));

			payMsg.setOut_trade_no(payMsg.getBankOrderId());
			// 设备号
			payMsg.setDevice_info(scanPayMsg.getDeviceInfo());
			// 商品描述
			payMsg.setBody(scanPayMsg.getGoodsBody());
			// 订单总金额
			payMsg.setTotal_fee(format(scanPayMsg.getAmount().multiply(new BigDecimal(100))));
			// 终端IP
			payMsg.setMch_create_ip(scanPayMsg.getMchCreateIp());
			// 通知地址
			payMsg.setNotify_url(scanPayMsg.getPayRuturnUrl());
			// 订单生成时间
			payMsg.setTime_start(scanPayMsg.getOrderDate());
			// 随机字符串
			payMsg.setNonce_str(String.valueOf(System.currentTimeMillis()));
			// 商品标识
			payMsg.setGoods_tag(scanPayMsg.getGoodsTag());
			// 是否限制信用卡
			payMsg.setLimit_credit_pay(scanPayMsg.getLimitCreditPay());
			payMsg.setCustomerID("");
			payMsg.setPayUrl(scanPayMsg.getPayUrl());
			payMsg.setPlainMessage(buildSignPlain(payMsg));
			BankLogUtils.printWeChatSdkManagerPaySendLog(payMsg);
			return wechatSdkPayServiceClient.payment(payMsg);
		} catch (Exception e) {
			logger.info(e.getMessage());
			throw new GopayException("app支付签名失败", e);
		}
	}

	public Object refund(BaseMessage baseMsg) throws GopayException {
		ScanPayBaseMessage scanPayMsg = (ScanPayBaseMessage) baseMsg;
		/**
		 * 根据订单号获取APPid,根据APPID获取商户号及商户KEY
		 */
		buildRefundMchInfo(scanPayMsg);
		
		SdkRefundReqMsg refundMsg = new SdkRefundReqMsg();
		BeanUtils.copyProperties(baseMsg, refundMsg);
		try {
			refundMsg.setService(wechatSdkPayConfig.get("WECHATSDK.REFUND.SEVICE"));
			refundMsg.setVersion(wechatSdkPayConfig.get("WECHATSDK.REFUND.VERSION"));
			refundMsg.setCharset(wechatSdkPayConfig.get("WECHATSDK.REFUND.CHARSET"));
			refundMsg.setSign_type(wechatSdkPayConfig.get("WECHATSDK.REFUND.SIGN.TYPE"));
			refundMsg.setMch_id(scanPayMsg.getMerID());
			refundMsg.setMchKey(scanPayMsg.getMchKey());
			 /**
             * 原交易上送银行订单号
             */
			refundMsg.setOut_trade_no(scanPayMsg.getTkOriBankOrderId());
            /**
             * 退款订单号
             */
			refundMsg.setOut_refund_no(scanPayMsg.getBankOrderId());
			refundMsg.setTotal_fee(format(scanPayMsg.getTkOriAmount().multiply(new BigDecimal(100))));
			refundMsg.setRefund_fee(format(scanPayMsg.getAmount().multiply(new BigDecimal(100))));
			// 操作员:操作员帐号,默认为商户号
			refundMsg.setOp_user_id(scanPayMsg.getMerID());
			// 退款渠道：ORIGINAL-原路退款，默认
			refundMsg.setRefund_channel("ORIGINAL");
			refundMsg.setNonce_str(String.valueOf(System.currentTimeMillis()));
			refundMsg.setPlainMessage(buildSignPlain(refundMsg));
			refundMsg.setRefundUrl(wechatSdkPayConfig.get("WECHATSDK.REFUND.URL"));
			BankLogUtils.printWeChatSdkManagerRefundSendLog(refundMsg);

			return wechatSdkPayServiceClient.refund(refundMsg);
		} catch (Exception e) {
			logger.info(e.getMessage());
			throw new GopayException("威富通app退款失败", e);
		}
	}

	public Object queryOrder(BaseMessage baseMsg) throws GopayException {
		ScanPayBaseMessage scanPayMsg = (ScanPayBaseMessage) baseMsg;
		
		/**
		 * 根据订单号获取APPid,根据APPID获取商户号及商户KEY
		 */
		buildMchInfo(scanPayMsg);
		
		SdkOrderQueryReqMsg queryMsg = new SdkOrderQueryReqMsg();
		BeanUtils.copyProperties(baseMsg, queryMsg);

		try {
			queryMsg.setService(wechatSdkPayConfig.get("WECHATSDK.ORDERQUERY.SEVICE"));
			queryMsg.setVersion(wechatSdkPayConfig.get("WECHATSDK.ORDERQUERY.VERSION"));
			queryMsg.setCharset(wechatSdkPayConfig.get("WECHATSDK.ORDERQUERY.CHARSET"));
			queryMsg.setSign_type(wechatSdkPayConfig.get("WECHATSDK.ORDERQUERY.SIGN.TYPE"));
			queryMsg.setMch_id(scanPayMsg.getMerID());
			queryMsg.setMchKey(scanPayMsg.getMchKey());
			queryMsg.setOut_trade_no(scanPayMsg.getBankOrderId());
			queryMsg.setNonce_str(String.valueOf(System.currentTimeMillis()));

			queryMsg.setPlainMessage(buildSignPlain(queryMsg));

			BankLogUtils.printWeChatSdkManagerQuerySendLog(queryMsg);
			return wechatSdkPayServiceClient.queryOrder(queryMsg);
		} catch (Exception e) {
			logger.info(e.getMessage());
			throw new GopayException("app支付订单查询失败", e);
		}
	}

	public Object refundQuery(Object msg) throws GopayException {
		// -- 待定 --
		ScanPayBaseMessage scanPayMsg = (ScanPayBaseMessage) msg;
		/**
		 * 根据订单号获取APPid,根据APPID获取商户号及商户KEY
		 */
		buildRefundMchInfo(scanPayMsg);
		
		SdkRefundQueryReqMsg refundQueryMsg = new SdkRefundQueryReqMsg();
		BeanUtils.copyProperties(msg, refundQueryMsg);
		refundQueryMsg.setService(wechatSdkPayConfig.get("WECHATSDK.REFUNDQUERY.SEVICE"));
		refundQueryMsg.setVersion(wechatSdkPayConfig.get("WECHATSDK.REFUNDQUERY.VERSION"));
		refundQueryMsg.setCharset(wechatSdkPayConfig.get("WECHATSDK.REFUNDQUERY.CHARSET"));
		refundQueryMsg.setSign_type(wechatSdkPayConfig.get("WECHATSDK.REFUNDQUERY.SIGN.TYPE"));
		refundQueryMsg.setMch_id(scanPayMsg.getMerID());
		refundQueryMsg.setMchKey(scanPayMsg.getMchKey());
		refundQueryMsg.setSign_agentno("");
		// 国付宝订单号
		refundQueryMsg.setOut_trade_no(scanPayMsg.getTkOriBankOrderId());
		refundQueryMsg.setTransaction_id("");
		/**
		 * 商户退款单号
		 */
		refundQueryMsg.setOut_refund_no(scanPayMsg.getBankOrderId());
		refundQueryMsg.setRefund_id("");
		refundQueryMsg.setNonce_str(String.valueOf(System.currentTimeMillis()));
		/**
		 * 中信渠道调用URL和查询一直，根据service参数区分是订单查询还是退款订单查询
		 */
		refundQueryMsg.setRefundQueryUrl(wechatSdkPayConfig.get("WECHATSDK.REFUNDQUERY.URL"));
		try {
			refundQueryMsg.setPlainMessage(buildSignPlain(refundQueryMsg));
		} catch (Exception e) {
			logger.info(e.getMessage());
			throw new GopayException("app退款订单查询失败", e);
		}
		BankLogUtils.printWeChatSdkManagerRefundQuerySendLog(refundQueryMsg);
		return wechatSdkPayServiceClient.refundQuery(refundQueryMsg);
	}

	public String buildSignPlain(Object obj) throws Exception {
		// 去掉多一个下划线的问题
		XStream xstream = new XStream(new DomDriver("UTF-8", new NoNameCoder()));
		xstream.processAnnotations(obj.getClass());
		return xstream.toXML(obj);
	}

	/**
	 * 金额格式化为整数
	 * 
	 * @param num
	 *            待格式化的金额
	 */
	private String format(BigDecimal num) {
		String numString = num.toString();
		if (numString.indexOf(".") != -1) {
			return StringUtils.substringBefore(numString, ".");
		}
		return numString;
	}

	 private static String modifyOrderId(String orderId, String chann) {
			//中信
			if ("15".equals(chann)) {
				orderId = "WF" + orderId.substring(2);
			}
			//兴业
			if ("16".equals(chann)) {
				orderId = "XY" + orderId.substring(2);
			}
			return orderId;
		}

	/**
	 * 
	 * 功能描述：设置商户ID及商户key
	 *
	 * @param baseMsg
	 * @return
	 * @throws GopayException
	 * 
	 * @author 宣广海
	 *
	 * @since 2016年9月26日
	 *
	 * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
	 */
	private BaseMessage buildMchInfo(BaseMessage baseMsg) throws GopayException {
		try {
			List<BankOrder> bankOrders = bankOrderDAO.getBankOrdersByGopayOrderId(baseMsg.getOrderId());
			if (bankOrders != null && bankOrders.size() == 1) {
				String appId = bankOrders.get(0).getAppId();
				String interCh=bankOrders.get(0).getInterfaceChennelCode();
				/**
				 * 根据APPID获取商户号和商户key
				 */
				CustAppInfo custAppInfo = bankCustAppInfoDAO.getCustAppInfo(appId,interCh);
				if (null != custAppInfo) {
					baseMsg.setMchKey(custAppInfo.getMerchantKey());
					baseMsg.setMerID(custAppInfo.getMerchantId());
					baseMsg.setAppId(appId);
				} else {
					throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
				}
			} else {
				throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
			throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002, ex);
		}
		return baseMsg;
	}
	private BaseMessage buildPaymentMchInfo(BaseMessage baseMsg) throws GopayException {
		try {
			String interCh = baseMsg.getBankIntrChann().value;
			if (StringUtils.isNotBlank(interCh)) {
				String appId =baseMsg.getAppId();
				logger.info("appId="+appId+",interCh="+interCh);
				/**
				 * 根据APPID获取商户号和商户key
				 */
				CustAppInfo custAppInfo = bankCustAppInfoDAO.getCustAppInfo(appId,interCh);
				if (null != custAppInfo) {
					baseMsg.setMchKey(custAppInfo.getMerchantKey());
					baseMsg.setMerID(custAppInfo.getMerchantId());
					baseMsg.setAppId(appId);
				} else {
					throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
				}
			} else {
				throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
			throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002, ex);
		}
		return baseMsg;
	}
	/**
	 * 
	 * @param baseMsg
	 * @return
	 * @throws GopayException
	 */
	private BaseMessage buildRefundMchInfo(BaseMessage baseMsg) throws GopayException {
		
		try {
			logger.info("进入退款构建报文，baseMsg.getTkOriBankOrderId()="+baseMsg.getTkOriBankOrderId());
			BankOrder bankOrder = bankOrderDAO.find(BankOrder.class, baseMsg.getTkOriBankOrderId());
			
			if (bankOrder != null) {
				String appId = bankOrder.getAppId();
				String interCh=bankOrder.getInterfaceChennelCode();
				logger.info("appId="+appId);
				/**
				 * 根据APPID获取商户号和商户key
				 */
				CustAppInfo custAppInfo = bankCustAppInfoDAO.getCustAppInfo(appId,interCh);
				if (null != custAppInfo) {
					baseMsg.setMchKey(custAppInfo.getMerchantKey());
					baseMsg.setMerID(custAppInfo.getMerchantId());
					baseMsg.setAppId(appId);
				} else {
					throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
				}
			} else {
				throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
			}
		} catch (Exception ex) {
			logger.info(ex.getMessage());
			throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002, ex);
		}
		return baseMsg;
	}

}
